// Copyright DustedPixels.com 2008. All rights reserved.

package com.dustedpixels.jasmin.unit.tools;

import java.lang.reflect.Field;

import com.dustedpixels.jasmin.unit.Unit;

/**
 * @author micapolos@gmail.com (Michal Pociecha-Los)
 */
public final class Pin {
  /**
   * Returns named pin of given unit.
   * 
   * @param unit 
   * @param fieldName
   * @return
   */
  public static Pin of(String pinName, Unit unit, String fieldName) {
    return new Pin(pinName, unit, fieldName, -1);
  }

  /**
   * Returns named pin of given unit.
   * 
   * @param unit 
   * @param fieldName
   * @return
   */
  public static Pin of(String pinName, Unit unit, String fieldName, int bit) {
    return new Pin(pinName, unit, fieldName, bit);
  }

  public final String pinName;
  public final Unit unit;
  public final String fieldName;
  public final int bit;
  
  private Pin(String pinName, Unit unit, String fieldName, int bit) {
    this.pinName = pinName;
    this.unit = unit;
    this.fieldName = fieldName;
    this.bit = bit;
  }
  
  public Sample sample() {
    try {
      Field field = unit.getClass().getDeclaredField(fieldName);
      Field zfield = null;
      try {
        zfield = unit.getClass().getDeclaredField(fieldName + "_Z");
      } catch (NoSuchFieldException e) {}
      
      Class<?> type = field.getType();
      if (type.getName().equals("int")) {
        int value = field.getInt(unit);
        int zvalue = (zfield != null) ? zfield.getInt(unit) : ~0;
        if (bit == -1) {
          return (zvalue == 0) ? Sample.HI_Z : Sample.MIXED(value);
        } else {
          if ((zvalue & (1 << bit)) != 0) {
            return ((value & (1 << bit)) != 0) ? Sample.HIGH : Sample.LOW;
          } else {
            return Sample.HI_Z;
          }
        }
      } else if (type.getName().equals("boolean")) {
        boolean value = field.getBoolean(unit);
        boolean zvalue = (zfield != null) ? zfield.getBoolean(unit) : true;
        if (zvalue) {
          return value ? Sample.HIGH : Sample.LOW;
        } else {
          return Sample.HI_Z;
        }
      } else {
        throw new RuntimeException();
      }
    } catch (SecurityException e) {
      throw new RuntimeException(e);
    } catch (NoSuchFieldException e) {
      throw new RuntimeException(e);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }
}
